import datetime

import pytz
from django.db import models, transaction
from django.db.models import F

from social.account.models import User
from social.exceptions import CodeException
from social.gift.models import Gift
from social.utils.models import BaseModel
from social.utils.shortcut import get_object_or_none


class UserLike(BaseModel):
    from_user = models.ForeignKey(User, related_name='like', on_delete=models.CASCADE)
    to_user = models.ForeignKey(User, related_name='like_by', on_delete=models.CASCADE)
    is_friend = models.BooleanField(default=False)

    @classmethod
    def is_follow(cls, from_user, to_user):
        return bool(get_object_or_none(UserLike, from_user=from_user, to_user=to_user))

    @classmethod
    def follow(cls, from_user, to_user):
        if UserBlock.is_blocked(to_user, from_user):
            raise CodeException(msg='你已被对方拉黑')
        if from_user.id == to_user.id:
            raise CodeException(msg='不能关注自己')
        with transaction.atomic():
            user_like, create = UserLike.objects.get_or_create(from_user=from_user, to_user=to_user)
            if create:
                user_like_to = get_object_or_none(UserLike, to_user=from_user, from_user=to_user)
                if user_like_to:
                    user_like_to.is_friend = True
                    user_like_to.save(update_fields=['is_friend'])

                    user_like.is_friend = True
                    user_like.save(update_fields=['is_friend'])

    @classmethod
    def cancel_follow(cls, from_user, to_user):
        with transaction.atomic():
            user_like = get_object_or_none(UserLike, from_user=from_user, to_user=to_user)
            if user_like:
                if user_like.is_friend:
                    user_like_by = get_object_or_none(UserLike, from_user=to_user, to_user=from_user)
                    user_like_by.is_friend = False
                    user_like_by.save(update_fields=['is_friend'])
                user_like.delete()

    class Meta:
        unique_together = [
            'from_user', 'to_user'
        ]
        index_together = [
            ('from_user', 'created_at'),
            ('to_user', 'created_at'),
            ('from_user', 'is_friend', 'created_at')
        ]


class UserVisit(BaseModel):
    from_user = models.ForeignKey(User, related_name='visit', on_delete=models.CASCADE)
    to_user = models.ForeignKey(User, related_name='visit_by', on_delete=models.CASCADE)
    times = models.IntegerField(default=0)

    class Meta:
        unique_together = [
            'from_user', 'to_user'
        ]


class UserBlock(BaseModel):
    from_user = models.ForeignKey(User, related_name='block', on_delete=models.CASCADE)
    to_user = models.ForeignKey(User, related_name='block_by', on_delete=models.CASCADE)

    @classmethod
    def is_block(cls, from_user, to_user):
        return bool(get_object_or_none(UserBlock, from_user=from_user, to_user=to_user))

    @classmethod
    def is_blocked(cls, from_user, to_user):
        return bool(get_object_or_none(UserBlock, from_user=to_user, to_user=from_user))

    @classmethod
    def block(cls, from_user, to_user):
        with transaction.atomic():
            UserBlock.objects.get_or_create(from_user=from_user, to_user=to_user)
            UserLike.cancel_follow(from_user=from_user, to_user=to_user)

    @classmethod
    def cancel_block(cls, from_user, to_user):
        user_block = get_object_or_none(UserBlock, from_user=from_user, to_user=to_user)
        if user_block:
            user_block.delete()

    class Meta:
        unique_together = [
            'from_user', 'to_user'
        ]


class UserPostCount(BaseModel):
    DAILY_MAX_COUNT = 3
    user = models.ForeignKey(User, related_name='post_count', on_delete=models.CASCADE)
    day = models.CharField(max_length=20)
    count = models.IntegerField(default=0)

    @classmethod
    def update_post_count(cls, user):
        now = datetime.datetime.now()
        date_tz = now.astimezone(pytz.timezone('Asia/Shanghai'))
        day = date_tz.strftime('%Y-%m-%d')
        post_count, _ = UserPostCount.objects.get_or_create(user=user, day=day)
        if post_count.count >= UserPostCount.DAILY_MAX_COUNT:
            raise CodeException(msg='当日可发布动态不能超过3条')
        post_count.count += 1
        post_count.save(update_fields=['count'])

    class Meta:
        unique_together = [
            'user', 'day'
        ]


class AVCallSetting(BaseModel):
    user = models.OneToOneField(User, related_name='av_call_setting', on_delete=models.CASCADE)
    call_enabled = models.BooleanField(default=True)
    setting_level = models.IntegerField(default=1)
    this_week_level = models.IntegerField(default=1)
    last_week_level = models.IntegerField(default=1)

    @property
    def call_price(self):
        if self.setting_level == 1:
            return 50, 25
        elif self.setting_level == 2:
            return 70, 35
        elif self.setting_level == 3:
            return 100, 50


class UserCallData(BaseModel):
    user = models.ForeignKey(User, related_name='call_data', on_delete=models.CASCADE)
    week = models.CharField(max_length=50)
    call_duration = models.IntegerField(default=0)
    accept_count = models.IntegerField(default=0)
    reject_count = models.IntegerField(default=0)
    total_count = models.IntegerField(default=0)

    @classmethod
    def key_week(cls, date):
        date_tz = date.astimezone(pytz.timezone('Asia/Shanghai'))
        cal = date_tz.isocalendar()
        return f"week_{cal[0]}-{cal[1]}"

    @property
    def call_level(self):
        call_duration = self.call_duration
        if call_duration <= 300:
            return 1
        elif call_duration <= 880:
            return 2
        else:
            return 3

    class Meta:
        unique_together = [
            'user', 'week'
        ]


class UserMsgSetting(BaseModel):
    user = models.OneToOneField(User, related_name='msg_setting', on_delete=models.CASCADE)
    new_msg = models.BooleanField(default=True, null=False)
    msg_summary = models.BooleanField(default=True, null=False)
    post_comment = models.BooleanField(default=True, null=False)
    post_like = models.BooleanField(default=True, null=False)
    new_fans = models.BooleanField(default=True, null=False)
    new_visited = models.BooleanField(default=True, null=False)
    special = models.BooleanField(default=True, null=False)


class UserLevel(BaseModel):
    user = models.OneToOneField(User, related_name='user_level', on_delete=models.CASCADE)
    wealth_value = models.IntegerField(default=0)
    charm_value = models.IntegerField(default=0)

    @property
    def wealth_level(self):
        value = self.wealth_value
        if value < 30:
            return 0
        elif value < 60:
            return 1
        elif value < 120:
            return 2
        elif value < 240:
            return 3
        elif value < 480:
            return 4
        elif value < 960:
            return 5
        elif value < 1920:
            return 6
        elif value < 3840:
            return 7
        elif value < 7680:
            return 8
        elif value < 15360:
            return 9
        elif value < 30720:
            return 10
        elif value < 61440:
            return 11
        elif value < 122880:
            return 12
        elif value < 245760:
            return 13
        elif value < 491520:
            return 14
        elif value < 983040:
            return 15
        elif value < 1966080:
            return 16
        elif value < 3932160:
            return 17
        elif value < 7864320:
            return 18
        elif value < 15728640:
            return 19
        else:
            return 20

    @property
    def charm_level(self):
        value = self.charm_value
        if value < 30:
            return 0
        elif value < 60:
            return 1
        elif value < 120:
            return 2
        elif value < 240:
            return 3
        elif value < 480:
            return 4
        elif value < 960:
            return 5
        elif value < 1920:
            return 6
        elif value < 3840:
            return 7
        elif value < 7680:
            return 8
        elif value < 15360:
            return 9
        elif value < 30720:
            return 10
        elif value < 61440:
            return 11
        elif value < 122880:
            return 12
        elif value < 245760:
            return 13
        elif value < 491520:
            return 14
        elif value < 983040:
            return 15
        elif value < 1966080:
            return 16
        elif value < 3932160:
            return 17
        elif value < 7864320:
            return 18
        elif value < 15728640:
            return 19
        else:
            return 20


class UserChatUp(BaseModel):
    from_user = models.ForeignKey(User, related_name='chat_up', on_delete=models.CASCADE)
    to_user = models.ForeignKey(User, related_name='chat_up_by', on_delete=models.CASCADE)

    @classmethod
    def is_chat_up(cls, from_user, to_user):
        return bool(get_object_or_none(UserChatUp, from_user=from_user, to_user=to_user))

    class Meta:
        unique_together = [
            'from_user', 'to_user'
        ]


class ChatUpCount(BaseModel):
    user = models.ForeignKey(User, related_name='chat_up_count', on_delete=models.CASCADE)
    day = models.CharField(max_length=20)
    count = models.IntegerField(default=0)

    @classmethod
    def check_count(cls, user):
        now = datetime.datetime.now()
        date_tz = now.astimezone(pytz.timezone('Asia/Shanghai'))
        day = date_tz.strftime('%Y-%m-%d')
        chat_count, _ = ChatUpCount.objects.get_or_create(user=user, day=day)
        max_count = 5 if user.is_vip else 3
        if chat_count.count >= max_count:
            raise CodeException(msg='今日搭讪次数已用尽')
        chat_count.count = F('count') + 1
        chat_count.save(update_fields=['count'])

    class Meta:
        unique_together = [
            'user', 'day'
        ]


class UserAuth(BaseModel):
    user = models.OneToOneField(User, related_name='auth', on_delete=models.CASCADE)
    cert_id = models.CharField(max_length=32)
    score = models.FloatField(default=0)
    oss_bucket_name = models.CharField(max_length=200, null=True)
    oss_object_name = models.CharField(max_length=200, null=True)

    @property
    def picture_url(self):
        return f'http://{self.oss_bucket_name}/{self.oss_object_name}'


class NameAuth(BaseModel):
    user = models.OneToOneField(User, related_name='name_auth', on_delete=models.CASCADE)
    cert_id = models.CharField(max_length=32)
    score = models.FloatField(default=0)
    oss_bucket_name = models.CharField(max_length=200, null=True)
    oss_object_name = models.CharField(max_length=200, null=True)
    cert_name = models.CharField(max_length=100, null=True)
    cert_no = models.CharField(max_length=18, null=True)
    status = models.IntegerField(default=0)


class GiftWall(BaseModel):
    gift = models.ForeignKey(Gift, related_name='gift_wall', on_delete=models.CASCADE)
    user = models.ForeignKey(User, related_name='gift_wall', on_delete=models.CASCADE)
    count = models.IntegerField(default=0)

    class Meta:
        unique_together = [
            ('user', 'gift'),
        ]
        index_together = [
            ('user', 'created_at')
        ]
